import requests
import json
import time
import asyncio
import uvloop
import random
import matplotlib.pyplot as plt
import matplotlib.dates as mdate
import pandas as pd
from datetime import datetime
import numpy as np

asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())


class regAndAuth():
    def __init__(self, login_url, register_jiami_url, register_url, auth_jiami_url, auth_url):
        self.login = login_url
        self.register_jiami_url = register_jiami_url
        self.register_url = register_url
        self.auth_jiami_url = auth_jiami_url
        self.auth_url = auth_url
        self.token = self.accessToken()

        self.headers_json = {
            'Authorization': self.token,
            'Content-Type': 'application/json'
        }
        self.headers_formdata = {
            'Authorization': self.token,
        }
        self.files = []

    def accessToken(self):
        """获取token"""
        headers = {
            'Content-Type': 'application/json'
        }
        payload_login = json.dumps({
            "username": "super_admin",
            "password": "5747cba9d15d3ad80507ed5b3cf84e25",
            "clientId": "frontend",
            "grantType": "password"
        })
        res = requests.request('POST', self.login, headers=headers, data=payload_login, verify=False).json()
        # print(res)
        # print( res['data']['accessToken'])
        return res['data']['accessToken']

    def require_res(self, url, headers, data):
        res = requests.request("POST", url, headers=headers, data=data, files=self.files, verify=False)
        return res.elapsed.total_seconds()

    async def auth(self, i):
        """授权加密 && 授权"""
        auth_payload_jiami = json.dumps({
            'oemCode': 'ECC17D16',
            'vehicleId': '0000000000000000',
            'refreshKey': "0",
            'type': 1,
        })

        response = requests.request("POST", self.auth_jiami_url, headers=self.headers_json, data=auth_payload_jiami,
                                    verify=False).json()
        auth_jiami_data = response['data']

        payload_auth = {'data': auth_jiami_data}
        while True:
            loop = asyncio.get_event_loop()
            current_time = time.time()
            # requests模块默认不支持异步操作，使用线程池来配合实现了。
            future = loop.run_in_executor(None, self.require_res, self.auth_url, self.headers_formdata, payload_auth)
            gap_time = await future

            time_stamp.append(time.strftime('%H:%M:%S', time.localtime(current_time)))
            statistus_all.append(gap_time)
            if time.time() - start_time > time_length:
                break
            if gap_time > 0.3:
                statistus_relay_list1.append(gap_time)
            else:
                statistus_relay_list2.append(gap_time)
            time.sleep(0.1)
            # if gap_time > 1:
            #     statistus_relay_list.append(gap_time)
            # else:
            #     statistus_list.append(gap_time)
            #     time.sleep(1 - gap_time)

    async def reg(self, i):
        """注册加密 && 注册"""
        while True:
            # current_time1 = time.time()
            m = str(time.time()).split('.')[0]
            rand = random.randint(1000, 9999)
            vehicleId = m + str(rand)
            reg_payload_jiami = json.dumps({
                'oemCode': 'ECC17D16',
                'vehicleId': vehicleId,
                'cityCode': 'changchun',
            })
            response = requests.request("POST", self.register_jiami_url, headers=self.headers_json,
                                        data=reg_payload_jiami,
                                        verify=False).json()
            reg_jiami_data = response['data']
            payload_reg = {'data': reg_jiami_data}

            loop = asyncio.get_event_loop()
            current_time2 = time.time()
            # requests模块默认不支持异步操作，所以就使用线程池来配合实现了。
            future = loop.run_in_executor(None, self.require_res, self.register_url, self.headers_formdata, payload_reg)
            gap_time = await future

            current_time3 = time.time()
            time_stamp.append(time.strftime('%H:%M:%S', time.localtime(current_time2)))
            statistus_all.append(gap_time)

            if gap_time > 0.3:
                statistus_relay_list1.append(gap_time)
            else:
                statistus_relay_list2.append(gap_time)
            if current_time3 - start_time > time_length:
                break

            # if 1 - gap_time < 0:
            #     statistus_relay_list.append(gap_time)
            # else:
            #     statistus_list.append(gap_time)
            #     gap2_time = current_time3 - current_time1
            #     if gap2_time < 1:
            #         time.sleep(1 - gap2_time)


def write_file(param):
    file_name = str(random.randint(1000,9999))+param + '_relay.txt'
    with open(file_name, mode='wt', encoding='utf8') as f1:
        # f1.write(str(statistus_list))
        # f1.write(str(statistus_relay_list))
        f1.write(str(statistus_relay_list1))
        f1.write(str(statistus_relay_list2))
        # f1.write('延迟在1s以内' + str(len(statistus_list)))
        # f1.write('延迟在1s以上' + str(len(statistus_relay_list)))
        f1.write('延迟在300ms以上' + str(len(statistus_relay_list1)))
        f1.write('延迟在300ms以内' + str(len(statistus_relay_list2)))


def draw_lines(x_list, y_list, param):
    count = 5  # 横坐标刻度数量

    ax = plt.gca()  # 表明设置图片的各个轴，plt.gcf()表示图片本身
    ax.xaxis.set_major_formatter(mdate.DateFormatter('%H:%M:%S'))  # 横坐标标签显示的日期格式

    # 相同日期去重
    array_after_distinct = []
    [array_after_distinct.append(j) for j in x_list if j not in array_after_distinct]  # array_samp=[0,2,4,6,8,10]

    # 设置横轴日期间隔
    x_length = len(array_after_distinct)
    x_gap = x_length / count
    array = []
    [array.append(j) for j in range(0,x_length,int(x_gap))]
    ax.set_xticks(array)  # 调用set_xticks函数画横轴刻度
    labels = [array_after_distinct[i] for i in array]  # 取出日期字符串
    ax.set_xticklabels(labels, rotation=40)  # 调用set_xticklabels函数，为横轴刻度附上标签，旋转40度

    # 正常输入横纵坐标轴数据
    avg_time = round(sum(statistus_all)/len(statistus_all),3)
    plt.plot(x_list, y_list, "-o", color='blue', linewidth=1 ,markersize=3,label='{} avg:{}'.format(param,avg_time))
    plt.ylabel('unit  s')
    plt.legend()
    plt.gcf().autofmt_xdate()
    plt.show()


async def main(param, person_num):
    if param == 'auth':
        # 1、授权并发
        tasks = [reg_and_auth.auth(i) for i in range(person_num)]

    elif param == 'reg':
        # 2、注册并发
        tasks = [reg_and_auth.reg(i) for i in range(person_num)]

    else:
        return

    done, pending = await asyncio.wait(tasks, timeout=None)  # timeout=None，等到所有任务完
    write_file(param)
    draw_lines(time_stamp, statistus_all, param)


if __name__ == '__main__':
    login_url = 'https://172.16.227.107:9001/v2x/platform/auth/user/login'
    register_jiami_url = "https://172.16.227.107:9001/v2x/platform/city/server/jiami"
    register_url = 'https://172.16.227.107:9001/v2x/platform/city/server/register'
    auth_jiami_url = "https://172.16.227.107:9001/v2x/platform/city/server/jiamiAuth"
    auth_url = 'https://172.16.227.107:9001/v2x/platform/city/server/auth'

    reg_and_auth = regAndAuth(login_url, register_jiami_url, register_url, auth_jiami_url, auth_url)

    # 统计授权请求时间
    statistus_list = []
    statistus_relay_list = []
    statistus_relay_list1 = []
    statistus_relay_list2 = []
    start_time = time.time()

    time_stamp = []
    statistus_all = []

    param = 'reg'  # param： reg： 注册； auth：授权
    # param = 'reg'      # param： reg： 注册； auth：授权
    time_length = 300  # 连续请求时长，单位s
    person_num = 10  # 同时并发个数

    loop = asyncio.get_event_loop()
    loop.run_until_complete(main(param, person_num))
